package com.xiaouyudeguang.common.config;

import com.xiaouyudeguang.common.cache.RedisCache;
import com.xiaouyudeguang.common.client.ClientInfo;
import com.xiaouyudeguang.common.constants.Headers;
import com.xiaouyudeguang.common.exception.BusinessException;
import com.xiaouyudeguang.common.utils.EnvironmentUtils;
import com.xiaouyudeguang.common.utils.SecurityUtils;
import com.xiaouyudeguang.common.utils.StringUtils;
import com.xiaouyudeguang.common.utils.UrlUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.ssssssss.magicapi.core.config.Constants;
import org.ssssssss.magicapi.core.context.MagicUser;
import org.ssssssss.magicapi.core.interceptor.AuthorizationInterceptor;
import org.ssssssss.magicapi.core.interceptor.RequestInterceptor;
import org.ssssssss.magicapi.core.model.ApiInfo;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletRequest;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletResponse;
import org.ssssssss.script.MagicScriptContext;

@Slf4j
@Component
public class CustomRequestInterceptor implements RequestInterceptor {

    @Autowired(required = false)
    private TokenStore tokenStore;

    @Autowired
    private ResourceServerConfig resourceServerConfig;

    @Autowired
    private AuthorizationInterceptor authorizationInterceptor;;

    @Override
    public Object preHandle(ApiInfo info, MagicScriptContext context, MagicHttpServletRequest request, MagicHttpServletResponse response) throws Exception {
        if (StringUtils.isNotBlank(request.getHeader("magic-token"))) {
            MagicUser user = authorizationInterceptor.getUserByToken(request.getHeader(Constants.MAGIC_TOKEN_HEADER));
            if (user != null) {
                return null;
            }
        }
        if (StringUtils.isBlank(request.getHeader(Headers.APP_ID))) {
            throw new BusinessException(Headers.APP_ID + " is required ");
        }
        if (StringUtils.isBlank(request.getHeader(Headers.TENANT_ID))) {
            throw new BusinessException(Headers.TENANT_ID + " is required");
        }
        RequestContextHolder.setRequestAttributes(RequestContextHolder.getRequestAttributes(), true);
        ClientInfo clientInfo = null;
        if (tokenStore == null) {
            clientInfo = resourceServerConfig.getClient();
            if (clientInfo == null) {
                throw new BusinessException(-System.currentTimeMillis());
            }
        }
        if ((EnvironmentUtils.isLocal() && StringUtils.isBlank(resourceServerConfig.getClientMode())) || UrlUtils.match(resourceServerConfig.getIgnoreUrls(), request.getRequestURI()) || (clientInfo != null && UrlUtils.match(clientInfo.getIgnoreUrls(), request.getRequestURI()))) {
            return null;
        }
        if (tokenStore == null && !(SecurityUtils.getAuthentication() instanceof AnonymousAuthenticationToken)) {
            return null;
        }
        String from = request.getHeader(Headers.FROM);
        String appId = request.getHeader(Headers.APP_ID);
        if (StringUtils.isNotBlank(from) && from.equals(appId)) {
            return null;
        }
        if (tokenStore == null) {
            throw new BusinessException(-System.currentTimeMillis(), "访问受限");
        }
        String token = request.getHeader(Headers.AUTHORIZATION);
        if (StringUtils.isBlank(token)) {
            throw new BusinessException(-System.currentTimeMillis(), "Token not found");
        }
        token = token.replace(OAuth2AccessToken.BEARER_TYPE.toLowerCase(), StringUtils.EMPTY).trim();
        if (token.startsWith("share:")) {
            token = RedisCache.get(token);
        }
        if (StringUtils.isBlank(token)) {
            throw new BusinessException(-System.currentTimeMillis(), "Token not found");
        }
        OAuth2AccessToken accessToken = tokenStore.readAccessToken(token);
        if (accessToken == null || StringUtils.isBlank(accessToken.getValue())) {
            throw new BusinessException(-System.currentTimeMillis(), "Token was not recognised");
        }
        if (accessToken.isExpired()) {
            throw new BusinessException(-System.currentTimeMillis(), "Token was expired");
        }
        OAuth2Authentication oAuth2Authentication = (OAuth2Authentication) tokenStore.readAuthentication(token);
        if (oAuth2Authentication == null) {
            throw new BusinessException(-System.currentTimeMillis(), "Token was not recognised");
        }
        SecurityContextHolder.getContext().setAuthentication(oAuth2Authentication);
        request.setAttribute(Headers.USER_ID, SecurityUtils.getUserId());
        return null;
    }

    /**
     * 接口执行之后
     *
     * @param info    接口信息
     * @param context 变量信息
     * @param value   即将要返回到页面的值
     */
    @Override
    public Object postHandle(ApiInfo info, MagicScriptContext context, Object value, MagicHttpServletRequest request, MagicHttpServletResponse response) throws Exception {
        return null;
    }
}